package de.revdev.llt.bean.managed;

import de.revdev.llt.bean.entities.FileCard;
import de.revdev.llt.bean.entities.FileCardBox;
import de.revdev.llt.bean.entities.LearnStatusFC;
import de.revdev.llt.bean.entities.LearnStatusFC.Status;
import de.revdev.llt.bean.entities.LearnStatusFCB;
import de.revdev.llt.bean.facade.FileCardBoxFacade;
import de.revdev.llt.bean.facade.FileCardFacade;
import de.revdev.llt.bean.facade.LearnStatusFCBFacade;
import de.revdev.llt.bean.facade.LearnStatusFCFacade;
import de.revdev.llt.bean.facade.UserFacade;
import de.revdev.llt.bean.utility.LearnStatusFCComperator;
import de.revdev.llt.bean.utility.MessageProvider;
import java.io.IOException;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.inject.Inject;
import javax.inject.Named;

/**
 *
 * @author f.lindermaier
 */
@Named(value = "learnWizardBean")
@ConversationScoped
public class LearnWizardBean implements Serializable {

    private List<LearnStatusFC> fileCardsToLearn;
    private FacesContext facesContext;
    private MessageProvider provider;
    private Conversation conversation;
    private LearnStatusFCFacade lsfcf;
    private LearnStatusFCBFacade lsfcbf;
    private UserFacade uf;
    private FileCardFacade fcf;
    private FileCardBoxFacade fcbf;
    private UserBean userBean;
    private ShowClassRoomBean showClassRoomBean;
    private LearnStatusFC currentLearnStatusFC;
    private LearnStatusFCB learnStatusFCB;
    private FileCardBox fileCardBox;
    private LinkedHashMap<String, LearnStatusFC.Status> learnCategory;
    private List<String> selectedCategories;
    private boolean showPanelChoose;
    private boolean showPanelStart;
    private boolean showPanelQuestion;
    private boolean showPanelAnswer;
    private boolean showPanelEnd;
    private boolean showRelearn;
    private static final Logger log = Logger.getLogger(LearnWizardBean.class.getName());

    /**
     * Creates a new instance of LearnWizardBean
     */
    public LearnWizardBean() {
    }

    @PostConstruct
    private void init() {
        fileCardsToLearn = new LinkedList<>();
        showPanelChoose = true;
        showPanelStart = false;
        showPanelQuestion = false;
        showPanelAnswer = false;
        showPanelEnd = false;
        showRelearn = false;
        learnCategory = new LinkedHashMap<>();
        learnCategory.put(provider.getValue("learn_name_category_unknown"), LearnStatusFC.Status.UNKNOWN);
        learnCategory.put(provider.getValue("learn_name_category_worst"), LearnStatusFC.Status.WORST);
        learnCategory.put(provider.getValue("learn_name_category_bad"), LearnStatusFC.Status.BAD);
        learnCategory.put(provider.getValue("learn_name_category_good"), LearnStatusFC.Status.GOOD);
        learnCategory.put(provider.getValue("learn_name_category_better"), LearnStatusFC.Status.BETTER);
        learnCategory.put(provider.getValue("learn_name_category_best"), LearnStatusFC.Status.BEST);
    }

    public void startLearning() {
        createLearnList();
        currentLearnStatusFC = fileCardsToLearn.get(0);
        showPanelChoose = false;
        showPanelStart = true;
        log.log(Level.INFO, "User {0} started a LearnSession ", learnStatusFCB.getUser().getId());
    }

    public void endLearning() {
        try {
            userBean.setClassRoomTemplate("/faces/user/showclassroom.xhtml");
            facesContext.getExternalContext().redirect("/LLTMaven/faces/user/classroom.xhtml?faces-redirect=true");
        } catch (IOException ex) {
            log.log(Level.SEVERE, "redirect could not been executed", ex);
        }
        log.log(Level.INFO, "User {0} finished a LearnSession ", learnStatusFCB.getUser().getId());
        conversation.end();
    }

    public int getSizeLstFileCardToLearn() {
        return fileCardsToLearn.size();
    }

    public void showInitialQuestion() {
        showPanelStart = false;
        showPanelQuestion = true;
    }

    public void showAnswer() {
        showPanelQuestion = false;
        showPanelAnswer = true;
    }

    public void evaluateAnswer(boolean isCorrect) {
        if (currentLearnStatusFC.getId() == null) {
            currentLearnStatusFC.setLearnStatusFCB(learnStatusFCB);
            lsfcf.create(currentLearnStatusFC);
            learnStatusFCB.getLearnStatusFC().add(currentLearnStatusFC);
            log.log(Level.INFO, "LearnStatusFC {0} was created", currentLearnStatusFC.getId());
        }
        currentLearnStatusFC.setLastDateAnswered(Calendar.getInstance().getTime());
        if (isCorrect) {
            if (currentLearnStatusFC.getLearnCategory() != LearnStatusFC.Status.BEST) {
                switch (currentLearnStatusFC.getLearnCategory()) {
                    case UNKNOWN:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.BAD);
                        break;
                    case WORST:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.BAD);
                        break;
                    case BAD:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.GOOD);
                        break;
                    case GOOD:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.BETTER);
                        break;
                    case BETTER:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.BEST);
                        break;
                }
            }
            currentLearnStatusFC.setCorrect(currentLearnStatusFC.getCorrect() + 1);
            lsfcf.edit(currentLearnStatusFC);
            userBean.setUser(uf.find(userBean.getUser().getId()));
            showRelearn = true;
        } else {
            if (currentLearnStatusFC.getLearnCategory() != LearnStatusFC.Status.WORST) {
                switch (currentLearnStatusFC.getLearnCategory()) {
                    case UNKNOWN:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.WORST);
                        break;
                    case BAD:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.WORST);
                        break;
                    case GOOD:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.BAD);
                        break;
                    case BETTER:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.GOOD);
                        break;
                    case BEST:
                        currentLearnStatusFC.setLearnCategory(LearnStatusFC.Status.BETTER);
                        break;
                }
            }
            currentLearnStatusFC.setNotcorrect(currentLearnStatusFC.getNotcorrect() + 1);
            lsfcf.edit(currentLearnStatusFC);
            userBean.setUser(uf.find(userBean.getUser().getId()));
            Collections.sort(fileCardsToLearn, new LearnStatusFCComperator());
            currentLearnStatusFC = fileCardsToLearn.get(0);
            showPanelAnswer = false;
            showPanelQuestion = true;
        }
        showClassRoomBean.refreshClassRoom();
        log.log(Level.INFO, "LearnStatusFC {0} was modified", currentLearnStatusFC.getId());
    }

    public void reLearnFileCard(boolean reLearn) {
        if (reLearn) {
            Collections.sort(fileCardsToLearn, new LearnStatusFCComperator());
            currentLearnStatusFC = fileCardsToLearn.get(0);
            showRelearn = false;
            showPanelAnswer = false;
            showPanelQuestion = true;
        } else {
            fileCardsToLearn.remove(currentLearnStatusFC);
            if (fileCardsToLearn.isEmpty()) {
                showRelearn = false;
                showPanelAnswer = false;
                showPanelEnd = true;
            } else {
                currentLearnStatusFC = fileCardsToLearn.get(0);
                showRelearn = false;
                showPanelAnswer = false;
                showPanelQuestion = true;
            }
        }
    }

    public void open(ActionEvent event) {
        long id = (long) event.getComponent().getAttributes().get("fcbid");
        userBean.setClassRoomTemplate("/faces/user/learnfilecards.xhtml");
        openLearningWithFCB(fcbf.find(id));
    }

    public String openLearningWithFCB(FileCardBox fileCardBox) {
        clear();
        conversation.begin();
        this.fileCardBox = fileCardBox;
        learnStatusFCB = lsfcbf.getLearnStatusForFileCardBox(userBean.getUser(), fileCardBox);
        if (learnStatusFCB == null) {
            learnStatusFCB = new LearnStatusFCB();
            learnStatusFCB.setUser(userBean.getUser());
            learnStatusFCB.setFileCardBox(fileCardBox);
            lsfcbf.create(learnStatusFCB);
            log.log(Level.INFO, "LearnStatusFCB {0} for User {1} and FileCardBox {2} was created", new Object[]{learnStatusFCB.getId(), userBean.getUser().getId(), fileCardBox.getId()});
            userBean.getUser().getLearnStatusFCBs().add(learnStatusFCB);
            uf.edit(userBean.getUser());
        }
        return "/faces/user/learn.xhtml?faces-redirect=true";
    }

    private void createLearnList() {
        fileCardsToLearn = new LinkedList<>();
        for (String cat : selectedCategories) {
            if (LearnStatusFC.Status.UNKNOWN == LearnStatusFC.Status.valueOf(cat)) {
                List<FileCard> lstFileCard = fcf.getUnknownCategorieFileCardsForFCB(fileCardBox, learnStatusFCB);
                for (FileCard fc : lstFileCard) {
                    LearnStatusFC lsfc = new LearnStatusFC();
                    lsfc.setFileCard(fc);
                    lsfc.setLearnCategory(LearnStatusFC.Status.valueOf(cat));
                    lsfc.setLearnStatusFCB(learnStatusFCB);
                    //Muss gesetzt werden, damit die Liste eindeutig sotiert werden kann zum testen
                    lsfc.setLastDateAnswered(Calendar.getInstance().getTime());
                    fileCardsToLearn.add(lsfc);
                }
            } else {
                List<LearnStatusFC> lstLearnStatusFC = lsfcf.getLearnStatusFCForLSFCBAndStatus(learnStatusFCB, LearnStatusFC.Status.valueOf(cat));
                for (LearnStatusFC lsfc : lstLearnStatusFC) {
                    fileCardsToLearn.add(lsfc);
                }
            }
        }
        Collections.sort(fileCardsToLearn, new LearnStatusFCComperator());
    }

    private void clear() {
        fileCardBox = null;
        learnStatusFCB = null;
        selectedCategories = null;
        fileCardsToLearn = null;
    }

    public String cancel() {
        clear();
        return "/faces/user/classromm.xhtml?faces-redirect=true";
    }

    public int getUnknownLearnStatus() {
        if (learnStatusFCB == null) {
            return fileCardBox.getFileCards().size();
        } else {
            return fileCardBox.getFileCards().size() - learnStatusFCB.getLearnStatusFC().size();
        }
    }

    public long getWorstStatusForFileCards() {
        if (learnStatusFCB == null) {
            return 0;
        } else {
            return lsfcf.countStatusFromFCB(LearnStatusFC.Status.WORST, learnStatusFCB);
        }
    }

    public long getBadStatusForFileCards() {
        if (learnStatusFCB == null) {
            return 0;
        } else {
            return lsfcf.countStatusFromFCB(LearnStatusFC.Status.BAD, learnStatusFCB);
        }
    }

    public long getGoodStatusForFileCards() {
        if (learnStatusFCB == null) {
            return 0;
        } else {
            return lsfcf.countStatusFromFCB(LearnStatusFC.Status.GOOD, learnStatusFCB);
        }
    }

    public long getBetterStatusForFileCards() {
        if (learnStatusFCB == null) {
            return 0;
        } else {
            return lsfcf.countStatusFromFCB(LearnStatusFC.Status.BETTER, learnStatusFCB);
        }
    }

    public long getBestStatusForFileCards() {
        if (learnStatusFCB == null) {
            return 0;
        } else {
            return lsfcf.countStatusFromFCB(LearnStatusFC.Status.BEST, learnStatusFCB);
        }
    }

    public String getCurrentFileCardHTMLFormattedAnswer() {
        return currentLearnStatusFC.getFileCard().getAnswer().replace("\n", "<br/>");
    }

    public String getCurrentFileCardHTMLFormattedQuestion() {
        return currentLearnStatusFC.getFileCard().getQuestion().replace("\n", "<br/>");
    }

    @Inject
    public void setUserBean(UserBean userBean) {
        this.userBean = userBean;
    }

    @Inject
    public void setConversation(Conversation conversation) {
        this.conversation = conversation;
    }

    @Inject
    public void setFacesContext(FacesContext facesContext) {
        this.facesContext = facesContext;
    }

    @Inject
    public void setLearnStatusFCFacade(LearnStatusFCFacade learnStatusFCFacade) {
        this.lsfcf = learnStatusFCFacade;
    }

    @Inject
    public void setLearnStatusFCBFacade(LearnStatusFCBFacade learnStatusFCBFacade) {
        this.lsfcbf = learnStatusFCBFacade;
    }

    @Inject
    public void setUserFacade(UserFacade userFacade) {
        this.uf = userFacade;
    }

    @Inject
    public void setFileCardFacade(FileCardFacade fileCardFacade) {
        this.fcf = fileCardFacade;
    }

    @Inject
    public void setMessageProvider(MessageProvider messageProvider) {
        this.provider = messageProvider;
    }

    @Inject
    public void setFileCardBoxFacade(FileCardBoxFacade fileCardBoxFacade) {
        this.fcbf = fileCardBoxFacade;
    }

    @Inject
    public void setShowClassRoomBean(ShowClassRoomBean showClassRoomBean) {
        this.showClassRoomBean = showClassRoomBean;
    }

    public List<LearnStatusFC> getFileCardsToLearn() {
        return fileCardsToLearn;
    }

    public void setFileCardsToLearn(List<LearnStatusFC> fileCardsToLearn) {
        this.fileCardsToLearn = fileCardsToLearn;
    }

    public LearnStatusFC getCurrentLearnStatusFC() {
        return currentLearnStatusFC;
    }

    public void setCurrentLearnStatusFC(LearnStatusFC currentLearnStatusFC) {
        this.currentLearnStatusFC = currentLearnStatusFC;
    }

    public LearnStatusFCB getLearnStatusFCB() {
        return learnStatusFCB;
    }

    public void setLearnStatusFCB(LearnStatusFCB learnStatusFCB) {
        this.learnStatusFCB = learnStatusFCB;
    }

    public FileCardBox getFileCardBox() {
        return fileCardBox;
    }

    public void setFileCardBox(FileCardBox fileCardBox) {
        this.fileCardBox = fileCardBox;
    }

    public LinkedHashMap<String, Status> getLearnCategory() {
        return learnCategory;
    }

    public void setLearnCategory(LinkedHashMap<String, Status> learnCategory) {
        this.learnCategory = learnCategory;
    }

    public List<String> getSelectedCategories() {
        return selectedCategories;
    }

    public void setSelectedCategories(List<String> selectedCategories) {
        this.selectedCategories = selectedCategories;
    }

    public boolean isShowPanelChoose() {
        return showPanelChoose;
    }

    public void setShowPanelChoose(boolean showPanelChoose) {
        this.showPanelChoose = showPanelChoose;
    }

    public boolean isShowPanelStart() {
        return showPanelStart;
    }

    public void setShowPanelStart(boolean showPanelStart) {
        this.showPanelStart = showPanelStart;
    }

    public boolean isShowPanelQuestion() {
        return showPanelQuestion;
    }

    public void setShowPanelQuestion(boolean showPanelQuestion) {
        this.showPanelQuestion = showPanelQuestion;
    }

    public boolean isShowPanelAnswer() {
        return showPanelAnswer;
    }

    public void setShowPanelAnswer(boolean showPanelAnswer) {
        this.showPanelAnswer = showPanelAnswer;
    }

    public boolean isShowPanelEnd() {
        return showPanelEnd;
    }

    public void setShowPanelEnd(boolean showPanelEnd) {
        this.showPanelEnd = showPanelEnd;
    }

    public boolean isShowRelearn() {
        return showRelearn;
    }

    public void setShowRelearn(boolean showRelearn) {
        this.showRelearn = showRelearn;
    }
}